// /////////////////////////////////////////////////////////////////////////////
//
// Name:            asGameState.cpp
// Author:          Michael Bartsch (ZCCdark203)
//
// Desc :           Binds the GameState class to AngelScript
//
// License:         Copyright (C) 2009 Michael Bartsch and Contributors
//
//                  This program is free software: you can redistribute it
//                  and/or modify it under the terms of the zlib/libpng License.
//                  See main.cpp for conditions of distribution and use.
//
// /////////////////////////////////////////////////////////////////////////////

// Include files
#include "asGameState.h"

#ifdef __COMPILE_WITH_ANGELSCRIPT__

#include "../ScriptHelper.h"

#include "../../core/GameState.h"


// ScriptedGameState class
// ScriptedGameState constructor
ScriptedGameState::ScriptedGameState(asIScriptObject *object)
: mObject(object)
{
    // No new state was created, so lets fix the IDs.
    mIDCount--;

    // Set up pointers which will be used.
    mObject->AddRef();
    mContext = GameManager::Instance()->getScriptManager()->getEngine()->CreateContext();

    // Retrieve data from the scripted GameState
    int id;

    // Get ID.
    id = mObject->GetObjectType()->GetMethodIdByDecl("u32 getID()");

    mContext->Prepare(id);
    mContext->SetObject(mObject);
    mContext->Execute();
    mID = mContext->GetReturnDWord();

    // Get the base entity.
    id = mObject->GetObjectType()->GetMethodIdByDecl("const Entity@ getBaseEntity()");

    mContext->Prepare(id);
    mContext->SetObject(mObject);
    mContext->Execute();
    mBaseEntity = static_cast<Entity*>(mContext->GetReturnObject());
}

// ScriptedGameState deconstructor
ScriptedGameState::~ScriptedGameState()
{
    mContext->Release();
    mObject->Release();
}

// Initialises the Game State.
void ScriptedGameState::init()
{
    int id = mObject->GetObjectType()->GetMethodIdByDecl("void init()");

    mContext->Prepare(id);
    mContext->SetObject(mObject);
    mContext->Execute();
}

// Clears the Game State.
void ScriptedGameState::clear()
{
    int id = mObject->GetObjectType()->GetMethodIdByDecl("void clear()");

    mContext->Prepare(id);
    mContext->SetObject(mObject);
    mContext->Execute();
}

// Updates the Game State.
void ScriptedGameState::update(f32 deltaTime)
{
    int id = mObject->GetObjectType()->GetMethodIdByDecl("void update(f32 deltaTime)");

    mContext->Prepare(id);
    mContext->SetObject(mObject);
    mContext->SetArgDWord(0, (asDWORD)deltaTime);
    mContext->Execute();
}

// Renders the Game State.
void ScriptedGameState::render()
{
    int id = mObject->GetObjectType()->GetMethodIdByDecl("void render()");

    mContext->Prepare(id);
    mContext->SetObject(mObject);
    mContext->Execute();
}

//! Reference factory for the GameState class.
GameState* createGameState()
{
    return new GameState();
}

//! Binds the GameState class to AngelScript.
void bindGameState(asIScriptEngine *engine)
{
    // Forward declarations.
    int r;

    // Bind GameState class.
    r = engine->RegisterObjectType("GameState", sizeof(GameState), asOBJ_REF); assert(r >= 0);

    // Set GameState behaviour.
    r = engine->RegisterObjectBehaviour("GameState", asBEHAVE_FACTORY, "GameState@ f()",
                                        asFUNCTION(createGameState), asCALL_CDECL); assert(r >= 0);
    r = engine->RegisterObjectBehaviour("GameState", asBEHAVE_ADDREF, "void f()",
                                        asMETHOD(GameState, grab), asCALL_THISCALL); assert(r >= 0);
    r = engine->RegisterObjectBehaviour("GameState", asBEHAVE_RELEASE, "void f()",
                                        asMETHOD(GameState, drop), asCALL_THISCALL); assert(r >= 0);

    r = engine->RegisterObjectMethod("GameState", "GameState& opAssign(const GameState &in)",
                                     asFUNCTION(assignT<GameState>), asCALL_CDECL_OBJFIRST); assert(r >= 0);

    // Bind GameState class functions.
    r = engine->RegisterObjectMethod("GameState", "void init()",
                                     asMETHOD(GameState, init), asCALL_THISCALL); assert(r >= 0);
    r = engine->RegisterObjectMethod("GameState", "void clear()",
                                     asMETHOD(GameState, clear), asCALL_THISCALL); assert(r >= 0);

    r = engine->RegisterObjectMethod("GameState", "void update(f32)",
                                     asMETHOD(GameState, update), asCALL_THISCALL); assert(r >= 0);
    r = engine->RegisterObjectMethod("GameState", "void render()",
                                     asMETHOD(GameState, render), asCALL_THISCALL); assert(r >= 0);

    r = engine->RegisterObjectMethod("GameState", "u32 getID()",
                                     asMETHOD(GameState, getID), asCALL_THISCALL); assert(r >= 0);
    r = engine->RegisterObjectMethod("GameState", "Entity@ getBaseEntity()",
                                     asMETHOD(GameState, getBaseEntity), asCALL_THISCALL); assert(r >= 0);

    // Define the interface for inheritance.
    r = engine->RegisterInterface("IGameState"); assert(r >= 0);

    r = engine->RegisterInterfaceMethod("IGameState", "void init()");
    r = engine->RegisterInterfaceMethod("IGameState", "void clear()");
    r = engine->RegisterInterfaceMethod("IGameState", "void update(f32)");
    r = engine->RegisterInterfaceMethod("IGameState", "void render()");
    r = engine->RegisterInterfaceMethod("IGameState", "u32 getID()");
    r = engine->RegisterInterfaceMethod("IGameState", "const Entity@ getBaseEntity()");

    // Define the class for inheritance.
    std::string decl = "class CGameState : IGameState, IHasSlots\n"
                       "{\n"
                       "    GameState @_inner;\n"
                       "    Entity @mBaseEntity;\n"
                       "\n"
                       "    CGameState()\n"
                       "    {\n"
                       "       @_inner = GameState();\n"
                       "       @mBaseEntity = _inner.getBaseEntity();\n"
                       "    }\n"
                       "\n"
                       "    void init() {}\n"
                       "    void clear() {}\n"
                       "    void update(f32 deltaTime) {}\n"
                       "    void render() {}\n"
                       "\n"
                       "    u32 getID() { return getID(); }\n"
                       "    const Entity@ getBaseEntity() { return mBaseEntity; }\n"
                       "}\n";

    GameManager::Instance()->getScriptManager()->addScriptSection("CGameState", decl);
}

#endif // __COMPILE_WITH_ANGELSCRIPT__

// End of File
